import { error, js } from "cc";
import Singleton from "./Singleton";


type EventCache = {
    target: any;
    func: Function;
    once: boolean;
};

export class EventDispatcher extends Singleton {
    /**
     * key: 事件名
     * value: 缓存事件
     */
    private _eventCacheMap: { [key: string]: any[] } = js.createMap();
    /**未找到监听事件的留存 */
    private _bufferMap: { [key: string]: [] } = js.createMap();
    /**是否自动清理监听留存  */
    private isAutoClearBufferMap: boolean = true;
    /**自动清理监听留存的时间 */
    static autoClearBufferTime = 0;

    static excludeEventNameLogList: string[] = [
    ];
    /**
     * 广播事件
     *
     * @param eventName 事件名
     * @param param 传递的剩余不定参数
     */
    public emit(eventName: string | string, ...param) {
        if (EventDispatcher.excludeEventNameLogList.indexOf(eventName) == -1) {
            // FrameWork.log("发送事件>>>>", eventName, param);
        }
        let eventCacheArray = this._eventCacheMap[eventName];
        if (eventCacheArray && eventCacheArray.length > 0) {
            let eventCache: EventCache = null;
            for (let i = 0; i < eventCacheArray.length; i++) {
                eventCache = eventCacheArray[i];
                // call 方法的语法和作用与 apply() 方法类似
                // 只有一个区别
                // 就是 call() 方法接受的是一个参数列表，而 apply() 方法接受的是一个包含多个参数的数组。
                eventCache.func.apply(eventCache.target, param);
            }
            for (let i = eventCacheArray.length - 1; i >= 0; i--) {
                eventCache = eventCacheArray[i];
                if (eventCache.once) {
                    eventCacheArray.splice(i, 1);
                }
            }
        } else {
            if (EventDispatcher.autoClearBufferTime > 0) {
                let eventCacheArray = this._bufferMap[eventName];
                if (!eventCacheArray) {
                    eventCacheArray = [];
                    this._bufferMap[eventName] = eventCacheArray
                }
                eventCacheArray.push(param as never);
                if (this.isAutoClearBufferMap) {
                    this.autoClearBuffer(eventName);
                }
            }
        }
    }
    /**自动清理未找到监听事件的留存 */
    private autoClearBuffer(eventName: string) {
        setTimeout(() => {
            if (this._bufferMap[eventName])
                delete this._bufferMap[eventName]
        }, EventDispatcher.autoClearBufferTime * 1000);
    }
    /**
     * 注册事件
     *
     * @param eventName 事件名
     * @param func 事件处理函数
     * @param target 事件处理函数的执行对象
     */
    public on(eventName: string, func: Function, target?: any) {
        if (!eventName) {
            error("EventDispatcher on eventName 不合法", eventName)
            return
        }
        this._on(eventName, func, target, false);
    }
    /**
     * 注册事件（接受函数执行一次后会自动销毁，不用主动off）
     *
     * @param eventName 事件名
     * @param func 事件处理函数
     * @param target 事件处理函数的执行对象
     */
    public onOnce(eventName: string, func: Function, target: any) {

        this._on(eventName, func, target, true);
    }
    /**
     * 注册事件
     *
     * @param eventName 事件名
     * @param func 事件处理函数
     * @param target 事件处理函数的执行对象
     * @param once 是否只回调一次
     */
    private _on(eventName: string, func: Function, target: any, once: boolean) {
        let eventCacheArray = this._eventCacheMap[eventName];
        if (!eventCacheArray) {
            eventCacheArray = [];
        }
        let isAddOn = true;
        if (eventCacheArray && eventCacheArray.length > 0) {
            for (let index = 0; index < eventCacheArray.length; index++) {
                const element: any = eventCacheArray[index];
                if (element.target == target && element.func == func) {
                    isAddOn = false;
                }
            }
        }
        if (isAddOn) {
            eventCacheArray.push({
                target: target,
                func: func,
                once: once,
            })
            this._eventCacheMap[eventName] = eventCacheArray;
        }
        if (Object.getOwnPropertyNames(this._bufferMap).length > 0) {
            let eventBufferArrays = this._bufferMap[eventName];
            if (eventBufferArrays) {
                for (let index = 0; index < eventBufferArrays.length; index++) {
                    const eventBufferArray: any[] = eventBufferArrays[index];
                    let newBuff = [eventName].concat(eventBufferArray);
                    this.emit.apply(this, newBuff);

                }
                delete this._bufferMap[eventName]
            }
        }

    }
    /**
     * 注销事件
     *
     * @param eventName 事件名
     * @param func 事件处理函数
     * @param target 事件处理函数的执行对象
     */
    public off(eventName: string, func?: Function, target?: any) {

        let eventCacheArray = this._eventCacheMap[eventName];

        if (eventCacheArray) {

            if (func && target) {

                for (let index = 0; index < eventCacheArray.length; index++) {

                    const element = eventCacheArray[index];

                    if (element.target == target && element.func) {

                        eventCacheArray.splice(index, 1);

                    }

                }

            } else {

                delete this._eventCacheMap[eventName];

            }

        }
    }
    /**
     * 注销某个已经注册的对象的所有事件
     * @param target 事件函数处理的执行对象
     */
    public targetOff(target: any) {

        for (const key in this._eventCacheMap) {

            let eventCacheArrays = this._eventCacheMap[key];

            for (let index = eventCacheArrays.length - 1; index >= 0; index--) {

                const eventCacheArray = eventCacheArrays[index];

                if (eventCacheArray[index].target == target) {

                    eventCacheArrays.splice(index, 1);

                }

            }

        }
    }
}


